/*
 * Copyright (c) 2013-2015 Charkey. All rights reserved.
 *
 * This software is the confidential and proprietary information of Charkey.
 * You shall not disclose such Confidential Information and shall use it only
 * in accordance with the terms of the agreements you entered into with Charkey.
 *
 * Charkey MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE SOFTWARE,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
 *
 * Charkey SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING,
 * MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 */

package cn.simastudio.talos.core.quartz;

import org.apache.shiro.session.mgt.SessionValidationScheduler;
import org.apache.shiro.session.mgt.ValidatingSessionManager;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Usage: Quartz session
 *
 * @author Charkey
 * @date 2015/5/25 17:24
 */
public class Quartz2SessionValidationScheduler implements SessionValidationScheduler {

    public static final long DEFAULT_SESSION_VALIDATION_INTERVAL = 3600000L;

    private static final String JOB_NAME = "SessionValidationJob";

    private static final Logger LOGGER = LoggerFactory.getLogger(Quartz2SessionValidationScheduler.class);

    private Scheduler scheduler;

    private boolean schedulerImplicitlyCreated = false;

    private boolean enabled = false;

    private ValidatingSessionManager sessionManager;

    private long sessionValidationInterval = 3600000L;

    public Quartz2SessionValidationScheduler() {
    }

    public Quartz2SessionValidationScheduler(
            ValidatingSessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }

    protected Scheduler getScheduler() throws SchedulerException {
        if (this.scheduler == null) {
            this.scheduler = StdSchedulerFactory.getDefaultScheduler();
            this.schedulerImplicitlyCreated = true;
        }
        return this.scheduler;
    }

    public void setScheduler(Scheduler scheduler) {
        this.scheduler = scheduler;
    }

    public void setSessionManager(ValidatingSessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }

    public boolean isEnabled() {
        return this.enabled;
    }

    public void setSessionValidationInterval(long sessionValidationInterval) {
        this.sessionValidationInterval = sessionValidationInterval;
    }

    public void enableSessionValidation() {
        LOGGER.debug("Scheduling session validation job using Quartz with session validation interval of {}ms.", this.sessionValidationInterval);
        try {
            SimpleTrigger trigger = TriggerBuilder
                    .newTrigger()
                    .startNow()
                    .withIdentity(JOB_NAME, "DEFAULT")
                    .withSchedule(
                            SimpleScheduleBuilder.simpleSchedule()
                                    .withIntervalInMilliseconds(
                                            sessionValidationInterval)).build();

            JobDetail detail = JobBuilder
                    .newJob(QuartzSessionValidationJob.class)
                    .withIdentity(JOB_NAME, "DEFAULT").build();
            detail.getJobDataMap().put("sessionManager", this.sessionManager);
            Scheduler scheduler = getScheduler();

            scheduler.scheduleJob(detail, trigger);
            if (this.schedulerImplicitlyCreated) {
                scheduler.start();
                LOGGER.debug("Successfully started implicitly created Quartz Scheduler instance.");
            }
            this.enabled = true;
            LOGGER.debug("Session validation job successfully scheduled with Quartz.");
        } catch (SchedulerException e) {
            if (LOGGER.isErrorEnabled()) {
                LOGGER.error("Error starting the Quartz session validation job. Session validation may not occurred. Reason: {}", e);
            }
        }
    }

    public void disableSessionValidation() {
        LOGGER.debug("Stopping Quartz session validation job...");
        Scheduler scheduler;
        try {
            scheduler = getScheduler();
            if (scheduler == null) {
                if (LOGGER.isWarnEnabled()) {
                    LOGGER.warn("getScheduler() method returned a null Quartz scheduler, which is unexpected.  Please check your configuration and/or implementation.  Returning quietly since there is no validation job to remove (scheduler does not exist).");
                }

                return;
            }
        } catch (SchedulerException e) {
            if (LOGGER.isWarnEnabled()) {
                LOGGER.warn("Unable to acquire Quartz Scheduler. Ignoring and returning (already stopped?), Reason: {}", e);
            }
            return;
        }
        try {
            scheduler.unscheduleJob(new TriggerKey("SessionValidationJob", "DEFAULT"));
            LOGGER.debug("Quartz session validation job stopped successfully.");
        } catch (SchedulerException e) {
            LOGGER.debug("Could not cleanly remove SessionValidationJob from Quartz scheduler. Ignoring and stopping. Reason: {}", e);
        }

        this.enabled = false;

        if (this.schedulerImplicitlyCreated)
            try {
                scheduler.shutdown();
            } catch (SchedulerException e) {
                if (LOGGER.isWarnEnabled())
                    LOGGER.warn("Unable to cleanly shutdown implicitly created Quartz Scheduler instance. Reason: {}", e);
            } finally {
                setScheduler(null);
                this.schedulerImplicitlyCreated = false;
            }
    }
}
